﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using l1cs.server.datatables;
using l1cs.server.model.Instance;
using l1cs.server.model.map;
using l1cs.server.server.types;
using l1cs.server.templates;
using l1cs.server.utils;

namespace l1cs.server.model.trap
{
    class L1MonsterTrap : L1Trap
    {
        private static Logger _log = Logger.getLogger( typeof( L1MonsterTrap ).FullName );

        private readonly int _npcId;
        private readonly int _count;

        private L1Npc _npcTemp = null; // パフォーマンスのためにキャッシュ
        //private Constructor _constructor = null; // パフォーマンスのためにキャッシュ

        public L1MonsterTrap( DataRow item )
            : base( item )
        {
            _npcId = SqlUtils.toInt( item["monsterNpcId"] );
            _count = SqlUtils.toInt( item["monsterCount"] );
        }

        private void addListIfPassable( List<Point> list, L1Map map, Point pt )
        {
            if ( map.isPassable( pt ) )
            {
                list.Add( pt );
            }
        }

        private List<Point> getSpawnablePoints( L1Location loc, int d )
        {
            List<Point> result = new List<Point>();
            L1Map m = loc.getMap();
            int x = loc.getX();
            int y = loc.getY();
            // locを中心に、1辺dタイルの正方形を描くPointリストを作る
            for ( int i = 0; i < d; i++ )
            {
                addListIfPassable( result, m, new Point( d - i + x, i + y ) );
                addListIfPassable( result, m, new Point( -( d - i ) + x, -i + y ) );
                addListIfPassable( result, m, new Point( -i + x, d - i + y ) );
                addListIfPassable( result, m, new Point( i + x, -( d - i ) + y ) );
            }
            return result;
        }

        //private Constructor getConstructor(L1Npc npc) throws ClassNotFoundException {
        //    return Class.forName(
        //            "l1j.server.server.model.Instance." + npc.getImpl()
        //                    + "Instance").getConstructors()[0];
        //}

        private L1NpcInstance createNpc()
        {
            if ( _npcTemp == null )
            {
                _npcTemp = NpcTable.getInstance().getTemplate( _npcId );
            }
            //if (_constructor == null) {
            //    _constructor = getConstructor(_npcTemp);
            //}
            Type t = Type.GetType( "l1cs.server.model.Instance." + _npcTemp.GetType().Name + "Instance" );
            object obj = t.InvokeMember( null,
                BindingFlags.CreateInstance,
                null, null,
                null );
            return (L1NpcInstance)obj;
        }

        private void spawn( L1Location loc )
        {
            L1NpcInstance npc = createNpc();
            npc.setId( IdFactory.getInstance().nextId() );
            npc.getLocation().set( loc );
            npc.setHomeX( loc.getX() );
            npc.setHomeY( loc.getY() );
            L1World.getInstance().storeObject( npc );
            L1World.getInstance().addVisibleObject( npc );

            npc.onNpcAI();
            npc.turnOnOffLight();
            npc.startChat( L1NpcInstance.CHAT_TIMING_APPEARANCE ); // チャット開始
        }

        override public void onTrod( L1PcInstance trodFrom, L1Object trapObj )
        {
            sendEffect( trapObj );

            List<Point> points = getSpawnablePoints( trapObj.getLocation(), 5 );

            // 沸ける場所が無ければ終了
            if ( points.Count == 0 )
            {
                return;
            }

            int cnt = 0;
            while ( true )
            {
                foreach ( Point pt in points )
                {
                    spawn( new L1Location( pt, trapObj.getMap() ) );
                    cnt++;
                    if ( _count <= cnt )
                    {
                        return;
                    }
                }
            }
        }
    }
}
